﻿    using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Collections;

namespace Wilke.SharePoint.Tools
{
    /// <summary>
    /// This class partially mocks the functionality of Microsoft.SharePoint.Administration.SPAspConfigurationFile
    /// </summary>
    internal static class WebConfigHelper
    {
        private static XmlNode EnsureElement(XmlNode xnRoot, string[] parentNodes, ref bool bChangesMade)
        {
            XmlDocument document = xnRoot as XmlDocument;
            document = (document != null) ? document : xnRoot.OwnerDocument;
            XmlNode node = xnRoot;
            foreach (string str in parentNodes)
            {
                XmlNode node2 = node.SelectSingleNode(str);
                if (node2 == null)
                {
                    XmlElement newChild = document.CreateElement(str);
                    node2 = node.AppendChild(newChild);
                    bChangesMade = true;
                }
                node = node2;
            }
            return node;
        }

        internal static bool EnsureSystemWebServerSection(XmlDocument xdWebConfig)
        {
            bool bChangesMade = false;
            EnsureElement(xdWebConfig, new string[] { "configuration", "system.webServer", "modules" }, ref bChangesMade);
            EnsureElement(xdWebConfig, new string[] { "configuration", "system.webServer", "handlers" }, ref bChangesMade);
            return bChangesMade;
        }

        internal static List<string> GetWebConfigNodes(XmlDocument xmlDocument)
        {
            Dictionary<int, string> parentNodes = new Dictionary<int, string>();
            StringBuilder buffer = new StringBuilder();
            List<string> stringCollection = new List<string>();

            XmlNodeReader xmlNodeReader = new XmlNodeReader(xmlDocument);

            string parentNodeName = String.Empty;
            string previousNodeName = String.Empty;
            int currentDepth = 0;
            List<string> nodesToIgnore = ConfigurationHelper.AutoLookupNodesToIgnore;
            bool skip = false;

            while (true)
            {
                if (skip)
                {
                    xmlNodeReader.Skip();
                }
                else
                {
                    xmlNodeReader.Read();
                }
                skip = false;
                switch (xmlNodeReader.NodeType)
                {
                    case XmlNodeType.XmlDeclaration:
                    case XmlNodeType.EndElement:
                    case XmlNodeType.EndEntity:
                    case XmlNodeType.Comment:
                    case XmlNodeType.ProcessingInstruction:
                    case XmlNodeType.Text:
                    case XmlNodeType.Attribute:
                        break;
                    default:
                        buffer.Length = 0;
                        if (xmlNodeReader.Depth > 0)
                        {
                            if (xmlNodeReader.Depth > currentDepth)
                            {
                                parentNodes[currentDepth] = previousNodeName;
                                currentDepth = xmlNodeReader.Depth;
                            }
                            else if (xmlNodeReader.Depth < currentDepth)
                            {
                                //currentDepth--;
                                currentDepth = xmlNodeReader.Depth;
                            }                            
                            if (!nodesToIgnore.Contains(xmlNodeReader.Name))
                            {
                                for (int i = 0; i < currentDepth; i++)
                                {
                                    buffer.Append(parentNodes[i]);
                                    buffer.Append("/");
                                }
                                buffer.Append(xmlNodeReader.Name);
                                if (xmlNodeReader.HasAttributes)
                                {
                                    bool uniqueAttributeFound = false;

                                    foreach (string knownAttributeName in ConfigurationHelper.DifferentiatingAttributeNames)
                                    {
                                        string attributeValue = xmlNodeReader.GetAttribute(knownAttributeName);
                                        if (!String.IsNullOrEmpty(attributeValue))
                                        {
                                            buffer.Append(String.Format("[@{0}='{1}']", knownAttributeName, attributeValue));
                                            uniqueAttributeFound = true;
                                            break;
                                        }
                                    }

                                    //If we did not find any of the known unique attribute names we just take the first one assuming 
                                    //this is the differentiating attribute in a collection of equally named nodes.
                                    if (!uniqueAttributeFound)
                                    {
                                        string attributeValue = xmlNodeReader.GetAttribute(0);
            
                                        if (xmlNodeReader.MoveToFirstAttribute())
                                        {
                                            buffer.Append(String.Format("[@{0}='{1}']", xmlNodeReader.Name, attributeValue));
                                        }
                                    }
                                }
                                stringCollection.Add(buffer.ToString());
                            }
                            else
                            {
                                skip = true;
                            }
                        }
                        else
                        {
                            stringCollection.Add(xmlNodeReader.Name);
                        }
                        break;
                }

                previousNodeName = xmlNodeReader.Name;

                if (xmlNodeReader.EOF)
                {
                    break;
                }
            }

            stringCollection.Sort();

            return (stringCollection);
        }
    }
}
